package cn.texous.web.parsing.book.publisher.fiction;

import cn.texous.util.commons.util.GsonUtils;
import cn.texous.util.commons.util.SnowFlake;
import cn.texous.util.commons.util.upgrade.Optional;
import cn.texous.web.parsing.book.concurrent.AnaThreadPoolExecutor;
import cn.texous.web.parsing.book.manager.RedisManager;
import cn.texous.web.parsing.book.model.bo.publisher.AnaCatalogAddOrUpdateBO;
import cn.texous.web.parsing.book.model.dto.AnaSearchChapterDTO;
import cn.texous.web.parsing.book.model.entity.mysql.AnaBookChapter;
import cn.texous.web.parsing.book.publisher.AnaSubscribe;
import cn.texous.web.parsing.book.service.api.mysql.AnaBookChapterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 章节目录搜索结果处理订阅器。
 * 需要保证这边只会有新增的章节
 *
 * @author Showa.L
 * @since 2019/7/25 19:21
 */
@Component
public class AnaCatalogSubscribe implements AnaSubscribe<AnaCatalogAddOrUpdateBO> {

    /**
     * 订阅事件 topic
     */
    public static final String TOPIC = "CATALOG_ADD";

    @Autowired
    private AnaBookChapterService anaBookChapterService;
    @Autowired
    private SnowFlake snowFlake;
    @Autowired
    private AnaThreadPoolExecutor anaThreadPoolExecutor;

    @Override
    public void onEvent(AnaCatalogAddOrUpdateBO object) {
        Optional.ofNullable(object)
                .map(AnaCatalogAddOrUpdateBO::getChapters)
                .ifPresent(cs -> insertOrUpdate(cs, object.getAnaBookCode()));
    }

    @Override
    public String getTopic() {
        return TOPIC;
    }

    /**
     * TODO 需要加锁，对目录内容进行保护，否则并发的时候，可能会造成前端目录加载出来但是找不到章节的情况，redis 也会出现重复的情况
     * @param chapters
     * @param anaBookCode
     */
    private void insertOrUpdate(List<AnaSearchChapterDTO> chapters, String anaBookCode) {
        Map<String, String> cacheChapters = new HashMap<>();
        List<AnaBookChapter> addChapters = new ArrayList<>();
        AtomicInteger number = new AtomicInteger();
        chapters.stream().forEach(c -> {
            AnaBookChapter bookChapter = new AnaBookChapter();
            String code = String.valueOf(snowFlake.nextId());
            bookChapter.setAnaBookCode(anaBookCode);
            bookChapter.setNumber(number.incrementAndGet());
            bookChapter.setName(c.getName());
            bookChapter.setWords(0);
            bookChapter.setUrl(c.getUrl());
            bookChapter.setCode(code);
            c.setCode(code);
            cacheChapters.put(bookChapter.getCode(), GsonUtils.toJson(bookChapter));
            addChapters.add(bookChapter);
        });
        if (!cacheChapters.isEmpty())
            RedisManager.cacheBookChapterInfo(cacheChapters, anaBookCode);
        if (!addChapters.isEmpty()) {
            anaThreadPoolExecutor.execute(() -> anaBookChapterService.insertIgnore(addChapters));
        }
    }
}
